package evo.engine
{
	import flash.events.Event;
	import flash.display.Sprite;
	import flash.utils.getTimer;
	import flash.display.DisplayObjectContainer;
	import flash.display.DisplayObject;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.utils.Dictionary;
	import flash.errors.IllegalOperationError;
	import flash.text.TextFormat;
	import flash.display.BlendMode;
	import flash.geom.Matrix;
	import flash.ui.Mouse;
	
	/**
	 * Core of demo engine player that outputs all effects to screen.
	 * 
	 */
	public class DemoEngine extends Bitmap
	{
		private var parts:Array;
		private var curPart:IDemoPart;
		
		private var currentEffect:IDemoEffect;
		private var currentEffects:Array;
		private var frameListeners:Array;	
		
		private var postProcessors:Dictionary;
		
		private var lastTime:uint;
		private var curTrigId:uint;				
		private var curPhase:uint=0;
		
		public var sync:Sequencer;
		public var buffer:BitmapData;
		
		public function DemoEngine(width:int, height:int)
		{
			buffer = new BitmapData(width, height, false, 0);
			super(buffer);
			parts = new Array();
			currentEffects = new Array();
			frameListeners = new Array();	
			buffer.lock();
			buffer.fillRect(buffer.rect, 0);
			buffer.unlock();
		}
		
		private function onPhase(t:uint):void {
			trace("Engine phase!", curPhase);
			curPhase += 1;
			curPart = parts[curPhase];
			if(curPart == null)
			{
				return;
			}
			curPart.init(this);
		}
		
		public function setSynch(sync:Sequencer):void
		{
			this.sync = sync;
			this.sync.phase.addListener(onPhase);
		}
						
		public function startDemo():void
		{
			Mouse.hide();
			this.sync.play(0*1000); // fast forward
			lastTime=getTimer();
			addEventListener("enterFrame", onFrame);
	
			curPart = parts[curPhase];
			curPart.init(this);		
		}
		
		public function addPart(part:IDemoPart):void
		{
			parts.push(part);
			part.preInit(this);
		}
		
		private function onFrame(evt:Event):void {	
			buffer.lock();
			buffer.fillRect(buffer.rect, 0);		
			this.sync.tick();
			
			if(curPart == null)
			{
				buffer.unlock();
				return;
			}	

			var time:uint=getTimer();
			var timedelta:uint=time-lastTime;
			curPart.prePlay(timedelta);	

			for each (var efx:IDemoEffect in currentEffects)
				efx.play(timedelta);
				
			curPart.postPlay(timedelta);	
			
			lastTime=time;	

			buffer.unlock();
		}
		
		public function removeEffect(efx:IDemoEffect):void
		{
			//trace('remove efx ' + efx);
			var tmp:Function = function(e:*, idx:int, arr:Array):Boolean {
				return e != efx;
			}
			currentEffects=currentEffects.filter(tmp);
		}
		
		public function addEffect(efx:IDemoEffect):void {
			efx.output = buffer;
			currentEffects.push(efx);
		}
	}
}